<template>
  <form class="el-form el-form--default el-form--label-right">

    <slot name="header"></slot>

    <slot></slot>

    <slot name="footer">
      <el-row style="text-align: right">
        <el-col>
          <el-button type="primary" @click="submitForm" :loading="loading">提交
          </el-button>
          <el-button @click="reset" :loading="loading">重置
          </el-button>
        </el-col>
      </el-row>
    </slot>
  </form>
</template>

<script lang="ts" setup>
import {onMounted, provide, ref, watch} from 'vue';
import FastForm from "@/lang/fast-form";
import Asserts from "@/lang/core/asserts";
import RejectException from "./reject-exception";

/**
 * SmartForm
 *
 * 业务上，包含: “初始化”、 “序列化” 和 “表单重置” 三个功能；
 * 界面上，控制了整体的布局方式，比如，当前我们使用的是栈格系统。
 */
interface SmartFormGroup {
    // 表单数据模型，允许是对象或者数组
    model: Array | object;
    // 表单类型：default|form-data|request-body
    type?: 'default' | 'data' | 'body';

    // 表单默认值
    object?: Record<string, any>;
    // 附加参数，提交表单时会附加到表单内容中
    attach?: Record<string, any>;

    // 表单布局：垂直/水平
    inline?: boolean;

    // 表单提交函数
    submit: ((params: Record<string, any> | FormData) => Promise<any>)
}

// 接收 props
const props = withDefaults(defineProps<SmartFormGroup>(), {
    type: 'default', inline: false, hiddenButton: false
});

Asserts.notBlank(props.model, "model is required!");

// FastForm 通过事件驱动，不要调用 reactive() 函数
const fastForm = new FastForm(props.model);

if (props.inline) {
    fastForm.theme = 'inline';
}

// 提供 FastForm 给所有子组件
provide('fast_form', fastForm);

// 是否正在加载
const loading = ref(false);

// 侦听 object 的变化
watch(() => props.object, (val) => {
    fastForm.setDefaultValue(val);
    fastForm.val(val);
});


/**
 * 验证表单是否有效
 */
const isValid = () => {
    return fastForm.isValid();
};

/**
 * 序列化成 FormData
 *
 * @return {FormData}
 */
const formData = () => {
    let res = fastForm.formData();
    if (props.attach) {
        for (let key in props.attach) {
            if (props.attach.hasOwnProperty(key)) {
                res.append(key, props.attach[key]);
            }
        }
    }
    return res;
};

/**
 * 序列化
 *
 * @return {object}
 */
const serialize = () => {
    let res = fastForm.serialize();
    if (props.attach) {
        for (let key in props.attach) {
            if (props.attach.hasOwnProperty(key)) {
                res[key] = props.attach[key];
            }
        }
    }
    return res;
};

/**
 * 重置表单
 *
 * 为表单渲染新的值，也可以通过设置 props.object 实现，效果是一样的
 *
 * @param obj {{}} 对象
 */
const val = (obj: any) => {
    fastForm.val(obj);
};

/**
 * 重置表单
 *
 * 并不是 cancel，而是使用默认值填充
 */
const reset = () => {
    fastForm.reset();
};

/**
 * 提交表单
 *
 * 内置提交表单的功能，使用给定的 url 和 method 进行提交
 */
const submitForm = () => {
    if (loading.value === true) {
        return;
    }
    if (!isValid()) {
        throw new RejectException('form is invalid!');
    } else {
        loading.value = true;
        const ret = props.type === 'default' ? serialize() : formData();
        props.submit(ret).finally(() => loading.value = false);
    }
};

// 控件初始化
onMounted(() => {
    // 这一行尽可能延迟加载，因为异步加载的问题，
    // 如果 input 组件未加载完成，可能会产生空指针相关的异常
    // 在 vue3 环境下，由此产生 bug 的概率较低
    if (props.object) {
        fastForm.setDefaultValue(props.object);
        fastForm.val(props.object);
    }
});

</script>